package com.huawei.chengdu.meetingdemo.util;

import android.util.Log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 日志工具类
 *
 * @author L00354002
 * @since 2022-9-30
 */
public class LogUtil {
    private static final String TAG = "MeetingDemoLog";

    // 日志写入文件开关
    private static volatile boolean LOG_WRITE_TO_FILE = true;

    // 日志文件路径
    private static String logPath = "";

    // 本类输出的日志文件名称
    private static final String LOG_NAME_SUFFIX = "-MeetingDemoLog.txt";

    // 日志的输出格式
    private static final DateTimeFormatter DATA_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS", Locale.ENGLISH);

    private static volatile char fileMark = 'a';

    private static final long MAX_SIZE = 1024 * 1024 * 2;

    private static int LOG_LEVEL = 2;

    private static final int ERROR_LOG_LEVEL = 0;

    private static final int INFO_LOG_LEVEL = 1;

    private static final int DEBUG_LOG_LEVEL = 2;

    private static final Executor LOG_EXECUTOR = new ThreadPoolExecutor(1, 10,
            5000L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(50));

    private static File dirsFile;

    public static void setLogWriteToFile(boolean logWriteToFile) {
        LOG_WRITE_TO_FILE = logWriteToFile;
    }

    public static int getLogLevel() {
        return LOG_LEVEL;
    }

    public static void setLogLevel(int logLevel) {
        LOG_LEVEL = logLevel;
    }

    public static void setLogPath(String path) {
        logPath = path;
        // 创建日志文件夹
        dirsFile = new File(logPath);
        if (!dirsFile.exists()) {
            boolean ret = dirsFile.mkdirs();
            if (!ret) {
                throw new RuntimeException("create log path failed!");
            }
        }
    }

    public static void error(String msg) {
        String filterMsg = filterSpecialCharacters(msg);
        Log.e(TAG, filterMsg);
        if (LOG_WRITE_TO_FILE) {
            LOG_EXECUTOR.execute(() -> writeLogToFile('E', TAG, filterMsg));
        }
    }

    public static void info(String msg) {
        if (LOG_LEVEL < INFO_LOG_LEVEL) {
            return;
        }
        String filterMsg = filterSpecialCharacters(msg);
        Log.i(TAG, filterMsg);
        if (LOG_WRITE_TO_FILE) {
            LOG_EXECUTOR.execute(() -> writeLogToFile('I', TAG, filterMsg));
        }
    }

    public static void debug(String msg) {
        if (LOG_LEVEL < DEBUG_LOG_LEVEL) {
            return;
        }
        String filterMsg = filterSpecialCharacters(msg);
        Log.d(TAG, filterMsg);
        if (LOG_WRITE_TO_FILE) {
            LOG_EXECUTOR.execute(() -> writeLogToFile('D', TAG, filterMsg));
        }
    }


    /**
     * 过滤特殊字符
     *
     * @param message 信息
     * @return 过滤特殊字符后的字符串
     */
    public static String filterSpecialCharacters(String message) {
        return message.replaceAll("\t|\r|\n|\b|\f|\u007F|\u000B|%0a|%0d|%0b|%7f|%08|%0c", "");
    }

    /**
     * 打开日志文件并写入日志
     *
     * @param logType logType
     * @param tag     tag
     * @param text    text
     */
    private static void writeLogToFile(char logType, String tag, String text) {
        LocalDateTime localDateTime = LocalDateTime.now();
        String needWriteMessage =
                localDateTime.format(DATA_FORMATTER) + "    " + logType + "    " + tag + "    " + text;
        File file;
        synchronized (LogUtil.class) {
            // 获取当前日志文件
            file = createLogFile(dirsFile);

            // 当前文件大小已满
            if (file.length() >= MAX_SIZE) {
                // 文件数量未满，创建新的日志文件
                if (fileMark < 'd') {
                    fileMark++;
                    deleteLogFile(dirsFile, fileMark + LOG_NAME_SUFFIX);
                } else {
                    // 文件数量已满，删除 *a-ShareLog.txt 文件
                    deleteLogFile(dirsFile, 'a' + LOG_NAME_SUFFIX);
                    fileMark = 'a';
                }
                file = createLogFile(dirsFile);
            }
        }
        // 写日志
        try (FileWriter filerWriter = new FileWriter(file, true);
             BufferedWriter bufWriter = new BufferedWriter(filerWriter)) {
            bufWriter.write(needWriteMessage);
            bufWriter.newLine();
            bufWriter.flush();
        } catch (IOException e) {
            throw new RuntimeException("Write to log file failed ...", e);
        }
    }

    /**
     * 创建日志文件
     *
     * @param parentDir parentDir
     * @return File
     */
    private static File createLogFile(File parentDir) {
        String fileName = fileMark + LOG_NAME_SUFFIX;
        // 创建文件
        File file = new File(parentDir, fileName);
        if (!file.exists()) {
            try {
                // 在指定的文件夹中创建文件
                boolean ret = file.createNewFile();
                if (!ret) {
                    throw new RuntimeException("Create new log file failed...");
                }
            } catch (IOException e) {
                throw new RuntimeException("Create log file failed...", e);
            }
        }
        return file;
    }

    /**
     * 删除日志文件
     *
     * @param parentDir parentDir
     * @param fileName  fileName
     */
    private static void deleteLogFile(File parentDir, String fileName) {
        File delFile = new File(parentDir, fileName);
        if (delFile.exists()) {
            if (!delFile.delete()) {
                throw new RuntimeException("delete old log failed...");
            }
        }
    }
}
